import java.util.ArrayList;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;

public class Map {
	/************ Singleton Pattern *************/
	static private Map instance = null;
	static Map getInstance() {
		if(instance == null){
			instance= new Map();
		}
		return instance;
	}
	/********************************************/
	
	
	static String defaultImageFilename = "img/walle.png";
	int backgroundColor = SWT.COLOR_WHITE;
	int width = 1000;
	int height = 600;
	int iteration = 0;
	int iterationTime = 250;
	
	boolean pause = true;
	
	Canvas canvas = null;
	
	ArrayList<Robot> robots = new ArrayList<Robot>();
	ArrayList<Robot> viruses = new ArrayList<Robot>();
	ArrayList<Bullet> bullets = new ArrayList<Bullet>();
	
	Robot selectedRobot = null;
	
	public void startGame(){
		canvas.getDisplay().timerExec(iterationTime, new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				if(!pause)
					iterate();

				
				if(iteration<=1500){
					canvas.getDisplay().timerExec(iterationTime,this);
				}
				else{
					Robot winner = null;
					if(!robots.isEmpty()){
						winner= robots.get(0);
					}
					for(Robot r: robots){
						if(r.killedRobots>winner.killedRobots){
							winner = r;
						}
						else if(r.killedRobots==winner.killedRobots){
							if(r.life > winner.life){
								winner = r;
							}
							else if (r.life > winner.life){
								if(r.credit > winner.credit){
									winner = r;
								}
							}
						}
					}
					
					MessageBox messageBox = new MessageBox((Shell)canvas.getParent());
					if(winner != null){
						messageBox.setText("Fim do jogo");
						messageBox.setMessage(winner.name+" ganhou o jogo. Eliminou "+ winner.killedRobots+" robots, ficou com "+winner.life+" de vida e com "+winner.credit+" creditos.");
					}
					messageBox.open();
					System.exit(0);
				}
			}
		});
	}
	
	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}
	
	public void iterate(){
		iteration++;
		notifyAllMapObjects();
		checkFires();
		canvas.redraw();
		
		System.err.println("iteration: " + iteration);
	}

	private void notifyAllMapObjects() {
		for(Robot robot: robots){
			robot.play();
		}
		for(Robot virus: viruses){
			virus.play();
		}
		for(Bullet bullet: bullets){
			bullet.play();
		}
	}

	private Map() {
		super();
	}
	
	public void selectRobot(Robot robot){
		Robot oldSelected = selectedRobot;
		selectedRobot = robot;
		
		//update toolbar
		Capabilities.getInstance().robotNameText.setText(robot.name);
		Capabilities.getInstance().robotAvatarText.setText(robot.avatarImageFilename);
		Capabilities.getInstance().robotXText.setText(""+robot.getX());
		Capabilities.getInstance().robotYText.setText(""+robot.getY());
		Capabilities.getInstance().robotCreditsText.setText(""+robot.credit);
		Capabilities.getInstance().robotLifeText.setText(""+robot.life);
		if(robot.attack!=null)
			robot.attack.select();
		if(robot.movement!=null)
			robot.movement.select();
		
		canvas.redraw(robot.getX()-(Robot.robotSize+Robot.robotBorder)/2, robot.getY()-(Robot.robotSize+Robot.robotBorder)/2, Robot.robotSize+Robot.robotBorder, Robot.robotSize+Robot.robotBorder, true);
		if(oldSelected!=null)
			canvas.redraw(oldSelected.getX()-(Robot.robotSize+Robot.robotBorder)/2, oldSelected.getY()-(Robot.robotSize+Robot.robotBorder)/2, Robot.robotSize+Robot.robotBorder, Robot.robotSize+Robot.robotBorder, true);
	}
	
	public Robot createRobot(int x, int y, String robotName, String filename){
		Robot robot = new Robot(x, y, robotName);
		if(filename!=null){
			robot.setAvatarImage(filename);
		}
		else{
			robot.setAvatarImage( defaultImageFilename);
		}
		robots.add(robot);
		return robot;
	}
	
	public void startGUI(Composite parent){
		canvas = new Canvas(parent, SWT.BACKGROUND | SWT.NO_REDRAW_RESIZE);
		canvas.setBounds(0, 0, width, height);
		
		canvas.addListener(SWT.Paint, new Listener () {
			public void handleEvent (Event e) {
				GC gc = e.gc;
				gc.setBackground(canvas.getDisplay().getSystemColor(backgroundColor));
				gc.fillRectangle(0, 0, width, height);
				
				System.out.println("paint called");
				if(selectedRobot!=null)
					selectedRobot.drawSelected(gc);
				for(Robot robot: robots){
					robot.drawDamage(gc);
				}
			}
		});
	}
	
	private int square(int var){
		return var*var;
	}
	
	public ArrayList<Robot> getNeighbour(MapObject mapObject, int range){
		ArrayList<Robot> ret = new ArrayList<Robot>();
		int squareDist;
		int squareRange = square(range);
		for(Robot neighbourRobot: robots){
			squareDist = square(neighbourRobot.getX()-mapObject.getX())+square(neighbourRobot.getY()-mapObject.getY());
			if(squareRange>= squareDist){
				ret.add(neighbourRobot);
			}
		}
		return ret;
	}
	
	/*
	//TODO: what to return
	public void getNeighbourRobot(Robot robot, int range){
		int creditPrice = range; //TODO: check price
		if(robot.credit < creditPrice){
			//TODO: refuse
		}
		getNeighbour(robot, range);
	}*/
	
	private void checkFires(){
		ArrayList<Robot> robots;
		for(int i=0; i< bullets.size(); i++){
			Bullet bullet = bullets.get(i);
			robots = getNeighbour(bullet, Bullet.bulletSize/2+Robot.robotSize/2);
			//percorrer o array ate encontrar o primeiro robot que esteja no raio da bala e nao tenha sido o criador da bala
			for(Robot hitedRobot: robots){
				if(hitedRobot != bullet.shooter){
					bullet.hit(hitedRobot);
					bullets.remove(i);i--;
					System.out.println( bullet.shooter.name + " hited "+hitedRobot.name+".");
					break;
				}
			}
		}
	}
	
	public void fire(Robot robot, int speed, int angle, int damage){
			double deltaXBullet = speed*Math.cos(angle*Math.PI/180) + robot.deltaX;
			double deltaYBullet = speed*Math.sin(angle*Math.PI/180) + robot.deltaY;
			bullets.add(new Bullet(robot, deltaXBullet, deltaYBullet, damage));
	}
	
	
}
